//
// Created by mio on 25-5-7.
//

#include "LoadBlanceConnection.h"

#include <chrono>

#define TIMEOUT 60

LoadBlanceConnection::LoadBlanceConnection(std::weak_ptr<LoadBlanceServer> loadblance_server,
    TaskScheduler* task_scheduler, int sockfd) :
    TcpConnection(task_scheduler, sockfd),
    loadblance_server_(loadblance_server),
    socket_(sockfd)
{
    this->SetReadCallback([this](std::shared_ptr<TcpConnection> conn, BufferReader& buffer)
    {
        return this->OnRead(buffer);
    });

    this->SetDisConnectCallback([this](std::shared_ptr<TcpConnection> conn)
    {
        this->DisConnect();
    });
}

LoadBlanceConnection::~LoadBlanceConnection()
{
}

bool LoadBlanceConnection::OnRead(BufferReader& buffer)
{
    if (buffer.ReadableBytes() > 0)
    {
        HandleMessage(buffer);
    }
    return true;
}

void LoadBlanceConnection::DisConnection()
{
}

bool LoadBlanceConnection::IsTimeout(uint64_t timestamp) // true是超时
{
    // 获取当前时间
    auto now = std::chrono::system_clock::now();
    auto nowTimestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();

    // 计算差值
    uint64_t time = nowTimestamp - timestamp;
    return abs(time) > TIMEOUT;
}

void LoadBlanceConnection::HandleMessage(BufferReader& buffer)
{
    if (buffer.ReadableBytes() < sizeof(packet_head)) return;
    packet_head* head = (packet_head*)buffer.Peek();
    if (buffer.ReadableBytes() < head->len) return;
    switch (head->cmd)
    {
    case LOGIN:
        HandleLogin(buffer);
        break;
    case MONITOR:
        HandleMonitorInfo(buffer);
        break;
    default:
        printf("CMD ERROR\n");
        break;
    }
    buffer.Retrieve(head->len);
}

void LoadBlanceConnection::HandleLogin(BufferReader& buffer)
{
    LoginReply reply;
    Login_Info* info = (Login_Info*)buffer.Peek();
    if (IsTimeout(info->timestamp))
    {
        reply.cmd = ERROR;
    }
    else
    {
        auto server = loadblance_server_.lock();
        if (server)
        {
            Monitor_body* monitor = server->GetMonitorInfo();
            reply.ip = monitor->ip;
            reply.port = monitor->port;

        }
        else
        {
            reply.cmd = ERROR;
        }
    }
    Send((const char*)&reply, reply.len);
}

void LoadBlanceConnection::HandleMonitorInfo(BufferReader& buffer)
{
    // 处理心跳
    Monitor_body* body = (Monitor_body*)buffer.Peek();
    auto server = loadblance_server_.lock();
    if (!server) return;
    server->UpdateMonitor(socket_, body);
}
